/*
 * 描          述:  <描述>
 * 修  改   人:  Administrator
 * 修改时间:  2018年5月27日
 * <修改描述:>
 */
package com.tx.core.method;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

import org.springframework.context.MessageSource;
import org.springframework.core.CoroutinesUtils;
import org.springframework.core.KotlinDetector;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.web.method.HandlerMethod;

import com.tx.core.method.container.NativeInvokeContainer;
import com.tx.core.method.databinder.NativeDataBinderFactory;
import com.tx.core.method.request.NativeInvokeRequest;
import com.tx.core.method.resolver.NativeMethodArgumentResolverComposite;

/**
 * 可调用的HandlerMethod<br/>
 *    该方法仅服务于本包内
 *    即本封装仅通过NativeHandlerMethodInvokeUtils对外提供服务<br/>
 * <功能详细描述>
 * 
 * @author  Administrator
 * @version  [版本号, 2018年5月27日]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
class NativeInvocableHandlerMethod extends HandlerMethod {
    
    /** 空参数 */
    private static final Object[] EMPTY_ARGS = new Object[0];
    
    /** 参数解析器 */
    private NativeMethodArgumentResolverComposite resolver;
    
    /** 参数名发现器 */
    private ParameterNameDiscoverer parameterNameDiscoverer;
    
    @Nullable
    private NativeDataBinderFactory dataBinderFactory;
    
    /** <默认构造函数> */
    public NativeInvocableHandlerMethod(HandlerMethod handlerMethod) {
        super(handlerMethod);
    }
    
    /** <默认构造函数> */
    public NativeInvocableHandlerMethod(Object bean, Method method) {
        super(bean, method);
    }
    
    /** <默认构造函数> */
    protected NativeInvocableHandlerMethod(Object bean, Method method,
            @Nullable MessageSource messageSource) {
        super(bean, method, messageSource);
    }
    
    /** <默认构造函数> */
    public NativeInvocableHandlerMethod(Object bean, String methodName,
            Class<?>... parameterTypes) throws NoSuchMethodException {
        super(bean, methodName, parameterTypes);
    }
    
    /**
     * 通过解析容器及请求中的方法参数，实现对方法的调用<br/>
     * @param request NativeWebRequest
     * @param mavContainer ModelAndViewContainer
     * @param providedArgs
     * @return the raw value returned by the invoked method
     * @throws Exception raised if no suitable argument resolver can be found,or if the method raised an exception
     * @see #getMethodArgumentValues
     * @see #doInvoke
     */
    @Nullable
    public Object invokeForRequest(NativeInvokeRequest request,
            @Nullable NativeInvokeContainer container, Object... providedArgs)
            throws Exception {
        Object[] args = getMethodArgumentValues(request,
                container,
                providedArgs);
        if (logger.isTraceEnabled()) {
            logger.trace("Arguments: " + Arrays.toString(args));
        }
        return doInvoke(args);
    }
    
    /**
     * 获取方法参数值<br/>
     * @since 5.1.2
     */
    protected Object[] getMethodArgumentValues(NativeInvokeRequest request,
            @Nullable NativeInvokeContainer container, Object... providedArgs)
            throws Exception {
        MethodParameter[] parameters = getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
        }
        
        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            MethodParameter parameter = parameters[i];
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            args[i] = findProvidedArgument(parameter, providedArgs);
            if (args[i] != null) {
                continue;
            }
            if (!this.resolver.supportsParameter(parameter)) {
                throw new IllegalStateException(
                        formatArgumentError(parameter, "No suitable resolver"));
            }
            try {
                args[i] = this.resolver.resolveArgument(parameter,
                        container,
                        request,
                        this.dataBinderFactory);
            } catch (Exception ex) {
                // Leave stack trace for later, exception may actually be resolved and handled...
                if (logger.isDebugEnabled()) {
                    String exMsg = ex.getMessage();
                    if (exMsg != null && !exMsg.contains(
                            parameter.getExecutable().toGenericString())) {
                        logger.debug(formatArgumentError(parameter, exMsg));
                    }
                }
                throw ex;
            }
        }
        return args;
    }
    
    /**
     * 调用方法<br/>
     * <功能详细描述>
     * @param args
     * @return
     * @throws Exception [参数说明]
     * 
     * @return Object [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Nullable
    protected Object doInvoke(Object... args) throws Exception {
        Method method = getBridgedMethod();
        try {
            if (KotlinDetector.isSuspendingFunction(method)) {
                return null;
            }
            return method.invoke(getBean(), args);
        } catch (IllegalArgumentException ex) {
            assertTargetBean(method, getBean(), args);
            String text = (ex.getMessage() != null ? ex.getMessage()
                    : "Illegal argument");
            throw new IllegalStateException(formatInvokeError(text, args), ex);
        } catch (InvocationTargetException ex) {
            Throwable targetException = ex.getTargetException();
            if (targetException instanceof RuntimeException) {
                throw (RuntimeException) targetException;
            } else if (targetException instanceof Error) {
                throw (Error) targetException;
            } else if (targetException instanceof Exception) {
                throw (Exception) targetException;
            } else {
                throw new IllegalStateException(
                        formatInvokeError("Invocation failure", args),
                        targetException);
            }
        }
    }
    
    /**
     * 设置值NativeDataBinderFactory<br/>
     * <功能详细描述>
     * @param dataBinderFactory [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public void setDataBinderFactory(
            NativeDataBinderFactory dataBinderFactory) {
        this.dataBinderFactory = dataBinderFactory;
    }
    
    /**
     * @return 返回 resolver
     */
    public NativeMethodArgumentResolverComposite getResolver() {
        return resolver;
    }
    
    /**
     * @param 对resolver进行赋值
     */
    public void setResolver(NativeMethodArgumentResolverComposite resolver) {
        this.resolver = resolver;
    }
    
    /**
     * @return 返回 parameterNameDiscoverer
     */
    public ParameterNameDiscoverer getParameterNameDiscoverer() {
        return parameterNameDiscoverer;
    }
    
    /**
     * @param 对parameterNameDiscoverer进行赋值
     */
    public void setParameterNameDiscoverer(
            ParameterNameDiscoverer parameterNameDiscoverer) {
        this.parameterNameDiscoverer = parameterNameDiscoverer;
    }
    
    /**
     * @return 返回 dataBinderFactory
     */
    public NativeDataBinderFactory getDataBinderFactory() {
        return dataBinderFactory;
    }
    
}
